﻿using MongoDB;
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Furion.DatabaseAccessor
{
    /// <summary>
    /// MongoDB 仓储接口
    /// </summary>
    /// <typeparam name="TDocument">实体类型</typeparam>
    public partial interface IMongoDbRepository<TDocument> : IMongoDbRepository<TDocument, string>
        where TDocument : IEntity<string>, new()
    {
    }
    /// <summary>
    /// MongoDB 非泛型仓储
    /// </summary>
    public partial interface IMongoDbRepository
    {
        /// <summary>
        /// 切换仓储
        /// </summary>
        /// <typeparam name="TDocument">实体类型</typeparam>
        /// <returns>仓储</returns>
        IMongoDbRepository<TDocument> Change<TDocument>()
            where TDocument : class, IEntity<string>, new();

        /// <summary>
        /// 切换仓储
        /// </summary>
        /// <typeparam name="TDocument">实体类型</typeparam>
        /// <typeparam name="TKey">主键类型</typeparam>
        /// <returns>仓储</returns>
        IMongoDbRepository<TDocument, TKey> Change<TDocument, TKey>()
            where TDocument : class, IEntity<TKey>, new()
            where TKey : class;

        /// <summary>
        /// 解析服务
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <returns></returns>
        TService GetService<TService>();
    }

    /// <summary>
    /// MongoDB 仓储接口
    /// </summary>
    /// <typeparam name="TDocument">实体类型</typeparam>
    /// <typeparam name="TKey">主键类型</typeparam>
    public partial interface IMongoDbRepository<TDocument, TKey>
        where TDocument : IEntity<TKey>, new()
        where TKey : class
    {
        /// <summary>
        /// 实体集合
        /// </summary>
        IMongoCollection<TDocument> Entities { get; }

        /// <summary>
        /// 数据库上下文
        /// </summary>
        IMongoDatabase DbContext { get; }

        /// <summary>
        /// 动态数据库上下文
        /// </summary>
        dynamic DynamicDbContext { get; }

        /// <summary>
        /// 判断是否存在
        /// </summary>
        /// <param name="predicate">条件</param>
        /// <returns></returns>
        bool Exists(Expression<Func<TDocument, bool>> predicate);
        /// <summary>
        /// 判断是否存在
        /// </summary>
        /// <param name="predicate">条件</param>
        /// <returns></returns>
        Task<bool> ExistsAsync(Expression<Func<TDocument, bool>> predicate);
        /// <summary>
        /// 获取记录数
        /// </summary>
        /// <returns></returns>
        long Count();
        /// <summary>
        /// 异步获取记录数
        /// </summary>
        /// <returns></returns>
        Task<long> CountAsync();
        /// <summary>
        /// 获取记录数
        /// </summary>
        /// <returns></returns>
        long Count(Expression<Func<TDocument, bool>> expression);
        /// <summary>
        /// 异步获取记录数
        /// </summary>
        /// <returns></returns>
        Task<long> CountAsync(Expression<Func<TDocument, bool>> expression);
        /// <summary>
        /// 获取记录数
        /// </summary>
        /// <returns></returns>
        long Count(FilterDefinition<TDocument> filter);
        /// <summary>
        /// 异步获取记录数
        /// </summary>
        /// <returns></returns>
        Task<long> CountAsync(FilterDefinition<TDocument> filter);

        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="pageIndex">页次</param>
        /// <param name="pageSize">页大小</param>
        /// <returns></returns>
        List<TDocument> PageList(int pageIndex, int pageSize);
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <typeparam name="TNewProjection">新实体类型</typeparam>
        /// <param name="pageIndex">页次</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="projection">新实体映射</param>
        /// <returns></returns>
        List<TNewProjection> PageList<TNewProjection>(int pageIndex, int pageSize,
            Expression<Func<TDocument, TNewProjection>> projection);
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="pageIndex">页次</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="filter">过滤器</param>
        /// <param name="sort">排序条件</param>
        /// <returns></returns>
        List<TDocument> PageList(int pageIndex, int pageSize, FilterDefinition<TDocument> filter, SortDefinition<TDocument> sort);
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <typeparam name="TNewProjection">新实体类型</typeparam>
        /// <param name="pageIndex">页次</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="filter">过滤器</param>
        /// <param name="sort">排序条件</param>
        /// <param name="projection">新实体映射</param>
        /// <returns></returns>
        List<TNewProjection> PageList<TNewProjection>(int pageIndex, int pageSize, FilterDefinition<TDocument> filter, SortDefinition<TDocument> sort, Expression<Func<TDocument, TNewProjection>> projection);
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="pageIndex">页次</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="where">筛选条件</param>
        /// <param name="sort">排序条件</param>
        /// <returns></returns>
        List<TDocument> PageList(int pageIndex, int pageSize, Expression<Func<TDocument, bool>> where, SortDefinition<TDocument> sort);
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <typeparam name="TNewProjection">新实体类型</typeparam>
        /// <param name="pageIndex">页次</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="where">筛选条件</param>
        /// <param name="sort">排序条件</param>
        /// <param name="projection">新实体映射</param>
        /// <returns></returns>
        List<TNewProjection> PageList<TNewProjection>(int pageIndex, int pageSize,
            Expression<Func<TDocument, bool>> where, SortDefinition<TDocument> sort, Expression<Func<TDocument, TNewProjection>> projection);
        /// <summary>
        /// 异步获取分页数据
        /// </summary>
        /// <param name="pageIndex">页次</param>
        /// <param name="pageSize">页大小</param>
        /// <returns></returns>
        Task<List<TDocument>> PageListAsync(int pageIndex, int pageSize);
        /// <summary>
        /// 异步获取分页数据
        /// </summary>
        /// <typeparam name="TNewProjection">新实体类型</typeparam>
        /// <param name="pageIndex">页次</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="projection">新实体映射</param>
        /// <returns></returns>
        Task<List<TNewProjection>> PageListAsync<TNewProjection>(int pageIndex, int pageSize,
            Expression<Func<TDocument, TNewProjection>> projection);
        /// <summary>
        /// 异步获取分页数据
        /// </summary>
        /// <param name="pageIndex">页次</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="filter">过滤器</param>
        /// <param name="sort">排序条件</param>
        /// <returns></returns>
        Task<List<TDocument>> PageListAsync(int pageIndex, int pageSize, FilterDefinition<TDocument> filter,
            SortDefinition<TDocument> sort);
        /// <summary>
        /// 异步获取分页数据
        /// </summary>
        /// <typeparam name="TNewProjection">新实体类型</typeparam>
        /// <param name="pageIndex">页次</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="filter">过滤器</param>
        /// <param name="sort">排序条件</param>
        /// <param name="projection">新实体映射</param>
        /// <returns></returns>
        Task<List<TNewProjection>> PageListAsync<TNewProjection>(int pageIndex, int pageSize,
            FilterDefinition<TDocument> filter, SortDefinition<TDocument> sort, Expression<Func<TDocument, TNewProjection>> projection);
        /// <summary>
        /// 异步获取分页数据
        /// </summary>
        /// <param name="pageIndex">页次</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="where">筛选条件</param>
        /// <param name="sort">排序条件</param>
        /// <returns></returns>
        Task<List<TDocument>> PageListAsync(int pageIndex, int pageSize, Expression<Func<TDocument, bool>> where,
            SortDefinition<TDocument> sort);
        /// <summary>
        /// 异步获取分页数据
        /// </summary>
        /// <typeparam name="TNewProjection">新实体类型</typeparam>
        /// <param name="pageIndex">页次</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="where">筛选条件</param>
        /// <param name="sort">排序条件</param>
        /// <param name="projection">新实体映射</param>
        /// <returns></returns>
        Task<List<TNewProjection>> PageListAsync<TNewProjection>(int pageIndex, int pageSize,
            Expression<Func<TDocument, bool>> where, SortDefinition<TDocument> sort, Expression<Func<TDocument, TNewProjection>> projection);

        /// <summary>
        /// 获取单个对象
        /// </summary>
        /// <param name="id">objectId</param>
        /// <returns></returns>
        TDocument Get(TKey id);
        /// <summary>
        /// 获取单个对象
        /// </summary>
        /// <param name="expression">筛选条件</param>
        /// <returns></returns>
        TDocument Get(Expression<Func<TDocument, bool>> expression);
        /// <summary>
        /// 获取单个对象
        /// </summary>
        /// <typeparam name="TNewProjection">新实体类型</typeparam>
        /// <param name="expression">筛选条件</param>
        /// <param name="projection">新实体映射</param>
        /// <returns></returns>
        TNewProjection Get<TNewProjection>(Expression<Func<TDocument, bool>> expression,
            Expression<Func<TDocument, TNewProjection>> projection);
        /// <summary>
        /// 获取单个对象
        /// </summary>
        /// <param name="filter">过滤器</param>
        /// <returns></returns>
        TDocument Get(FilterDefinition<TDocument> filter);
        /// <summary>
        /// 获取单个对象
        /// </summary>
        /// <typeparam name="TNewProjection">新实体类型</typeparam>
        /// <param name="filter">过滤器</param>
        /// <param name="projection">新实体映射</param>
        /// <returns></returns>
        TNewProjection Get<TNewProjection>(FilterDefinition<TDocument> filter,
            Expression<Func<TDocument, TNewProjection>> projection);
        /// <summary>
        /// 异步获取单个对象
        /// </summary>
        /// <param name="id">objectId</param>
        /// <returns></returns>
        Task<TDocument> GetAsync(TKey id);
        /// <summary>
        /// 异步获取单个对象
        /// </summary>
        /// <param name="expression">筛选条件</param>
        /// <returns></returns>
        Task<TDocument> GetAsync(Expression<Func<TDocument, bool>> expression);
        /// <summary>
        /// 异步获取单个对象
        /// </summary>
        /// <typeparam name="TNewProjection">新实体类型</typeparam>
        /// <param name="expression">筛选条件</param>
        /// <param name="projection">新实体映射</param>
        /// <returns></returns>
        Task<TNewProjection> GetAsync<TNewProjection>(Expression<Func<TDocument, bool>> expression,
            Expression<Func<TDocument, TNewProjection>> projection);
        /// <summary>
        /// 异步获取单个对象
        /// </summary>
        /// <param name="filter">过滤器</param>
        /// <returns></returns>
        Task<TDocument> GetAsync(FilterDefinition<TDocument> filter);
        /// <summary>
        /// 异步获取单个对象
        /// </summary>
        /// <typeparam name="TNewProjection">新实体类型</typeparam>
        /// <param name="filter">过滤器</param>
        /// <param name="projection">新实体映射</param>
        /// <returns></returns>
        Task<TNewProjection> GetAsync<TNewProjection>(FilterDefinition<TDocument> filter,
            Expression<Func<TDocument, TNewProjection>> projection);
        /// <summary>
        /// 查询
        /// </summary>
        /// <typeparam name="TNewProjection">新实体类型</typeparam>
        /// <param name="expression">筛选条件</param>
        /// <param name="projection">新实体映射</param>
        /// <returns></returns>
        List<TNewProjection> Find<TNewProjection>(Expression<Func<TDocument, bool>> expression,
            Expression<Func<TDocument, TNewProjection>> projection);
        /// <summary>
        /// 查询
        /// </summary>
        /// <param name="filter">过滤器</param>
        /// <returns></returns>
        List<TDocument> Find(FilterDefinition<TDocument> filter);
        /// <summary>
        /// 查询
        /// </summary>
        /// <typeparam name="TNewProjection">新实体类型</typeparam>
        /// <param name="filter">过滤器</param>
        /// <param name="projection">新实体映射</param>
        /// <returns></returns>
        List<TNewProjection> Find<TNewProjection>(FilterDefinition<TDocument> filter,
            Expression<Func<TDocument, TNewProjection>> projection);
        /// <summary>
        /// 查询
        /// </summary>
        /// <typeparam name="TNewProjection">新实体类型</typeparam>
        /// <param name="expression">筛选条件</param>
        /// <param name="projection">新实体映射</param>
        /// <returns></returns>
        Task<List<TNewProjection>> FindAsync<TNewProjection>(Expression<Func<TDocument, bool>> expression,
            Expression<Func<TDocument, TNewProjection>> projection);
        /// <summary>
        /// 查询
        /// </summary>
        /// <param name="filter">过滤器</param>
        /// <returns></returns>
        Task<List<TDocument>> FindAsync(FilterDefinition<TDocument> filter);
        /// <summary>
        /// 查询
        /// </summary>
        /// <typeparam name="TNewProjection">新实体类型</typeparam>
        /// <param name="filter">过滤器</param>
        /// <param name="projection">新实体映射</param>
        /// <returns></returns>
        Task<List<TNewProjection>> FindAsync<TNewProjection>(FilterDefinition<TDocument> filter,
            Expression<Func<TDocument, TNewProjection>> projection);
        /// <summary>
        /// 插入
        /// </summary>
        /// <param name="value">对象</param>
        void Insert(TDocument value);
        /// <summary>
        /// 异步插入
        /// </summary>
        /// <param name="value">对象</param>
        /// <returns></returns>
        Task InsertAsync(TDocument value);
        /// <summary>
        /// 批量插入
        /// </summary>
        /// <param name="values">对象集合</param>
        void BatchInsert(IEnumerable<TDocument> values);
        /// <summary>
        /// 异步批量插入
        /// </summary>
        /// <param name="values">对象集合</param>
        /// <returns></returns>
        Task BatchInsertAsync(IEnumerable<TDocument> values);
        /// <summary>
        /// 局部更新
        /// </summary>
        /// <param name="id">记录ID</param>
        /// <param name="update">更新条件</param>
        /// <returns></returns>
        UpdateResult Update(TKey id, UpdateDefinition<TDocument> update);
        /// <summary>
        /// 局部更新
        /// </summary>
        /// <param name="id">记录ID</param>
        /// <param name="update">更新条件</param>
        /// <returns></returns>
        Task<UpdateResult> UpdateAsync(TKey id, UpdateDefinition<TDocument> update);
        /// <summary>
        /// 局部更新
        /// </summary>
        /// <param name="filter">过滤器</param>
        /// <param name="update">更新条件</param>
        /// <returns></returns>
        UpdateResult Update(FilterDefinition<TDocument> filter, UpdateDefinition<TDocument> update);
        /// <summary>
        /// 异步局部更新（仅更新一条记录）
        /// </summary>
        /// <param name="filter">过滤器</param>
        /// <param name="update">更新条件</param>
        /// <returns></returns>
        Task<UpdateResult> UpdateAsync(FilterDefinition<TDocument> filter, UpdateDefinition<TDocument> update);
        /// <summary>
        /// 局部更新（仅更新一条记录）
        /// </summary>
        /// <param name="expression">筛选条件</param>
        /// <param name="update">更新条件</param>
        /// <returns></returns>
        UpdateResult Update(Expression<Func<TDocument, bool>> expression,
            UpdateDefinition<TDocument> update);
        /// <summary>
        /// 异步局部更新（仅更新一条记录）
        /// </summary>
        /// <param name="expression">筛选条件</param>
        /// <param name="update">更新条件</param>
        /// <returns></returns>
        Task<UpdateResult> UpdateAsync<T>(Expression<Func<TDocument, bool>> expression,
            UpdateDefinition<TDocument> update);
        /// <summary>
        /// 局部更新（更新多条记录）
        /// </summary>
        /// <param name="expression">筛选条件</param>
        /// <param name="update">更新条件</param>
        /// <returns></returns>
        UpdateResult UpdateMany(Expression<Func<TDocument, bool>> expression,
            UpdateDefinition<TDocument> update);
        /// <summary>
        /// 异步局部更新（更新多条记录）
        /// </summary>
        /// <param name="expression">筛选条件</param>
        /// <param name="update">更新条件</param>
        /// <returns></returns>
        Task<UpdateResult> UpdateManyAsync(Expression<Func<TDocument, bool>> expression,
            UpdateDefinition<TDocument> update);
        /// <summary>
        /// 局部更新（仅更新一条记录）
        ///     <para><![CDATA[expression 参数示例：x => x.Id == 1 && x.Age > 18 && x.Gender == 0]]></para>
        ///     <para><![CDATA[entity 参数示例：y => new T{ RealName = "Ray", Gender = 1}]]></para>
        /// </summary>
        /// <param name="expression">筛选条件</param>
        /// <param name="entity">更新条件</param>
        /// <returns></returns>
        UpdateResult Update(Expression<Func<TDocument, bool>> expression,
            Expression<Action<TDocument>> entity);
        /// <summary>
        /// 异步局部更新（仅更新一条记录）
        ///     <para><![CDATA[expression 参数示例：x => x.Id == 1 && x.Age > 18 && x.Gender == 0]]></para>
        ///     <para><![CDATA[entity 参数示例：y => new T{ RealName = "Ray", Gender = 1}]]></para>
        /// </summary>
        /// <param name="expression">筛选条件</param>
        /// <param name="entity">更新条件</param>
        /// <returns></returns>
        Task<UpdateResult> UpdateAsync(Expression<Func<TDocument, bool>> expression,
            Expression<Action<TDocument>> entity);
        /// <summary>
        /// 覆盖更新
        /// </summary>
        /// <param name="value">对象</param>
        /// <returns></returns>
        ReplaceOneResult Update(TDocument value);
        /// <summary>
        /// 异步覆盖更新
        /// </summary>
        /// <param name="value">对象</param>
        /// <returns></returns>
        Task<ReplaceOneResult> UpdateAsync(TDocument value);
        /// <summary>
        /// 删除指定对象
        /// </summary>
        /// <param name="id">对象Id</param>
        /// <returns></returns>
        DeleteResult Delete(TKey id);
        /// <summary>
        /// 异步删除指定对象
        /// </summary>
        /// <param name="id">对象Id</param>
        /// <returns></returns>
        Task<DeleteResult> DeleteAsync(TKey id);
        /// <summary>
        /// 删除指定对象
        /// </summary>
        /// <param name="expression">查询条件</param>
        /// <returns></returns>
        DeleteResult Delete(Expression<Func<TDocument, bool>> expression);
        /// <summary>
        /// 异步删除指定对象
        /// </summary>
        /// <param name="expression">查询条件</param>
        /// <returns></returns>
        Task<DeleteResult> DeleteAsync(Expression<Func<TDocument, bool>> expression);
        /// <summary>
        /// 批量删除对象
        /// </summary>
        /// <param name="ids">ID集合</param>
        /// <returns></returns>
        DeleteResult BatchDelete(IEnumerable<ObjectId> ids);
        /// <summary>
        /// 异步批量删除对象
        /// </summary>
        /// <param name="ids">ID集合</param>
        /// <returns></returns>
        Task<DeleteResult> BatchDeleteAsync(IEnumerable<ObjectId> ids);
        /// <summary>
        /// 批量删除对象
        /// </summary>
        /// <param name="filter">过滤器</param>
        /// <returns></returns>
        DeleteResult BatchDelete(FilterDefinition<TDocument> filter);
        /// <summary>
        /// 异步批量删除对象
        /// </summary>
        /// <param name="filter">过滤器</param>
        /// <returns></returns>
        Task<DeleteResult> BatchDeleteAsync(FilterDefinition<TDocument> filter);
        /// <summary>
        /// 批量删除对象
        /// </summary>
        /// <param name="expression">筛选条件</param>
        /// <returns></returns>
        DeleteResult BatchDelete(Expression<Func<TDocument, bool>> expression);
        /// <summary>
        /// 异步批量删除对象
        /// </summary>
        /// <param name="expression">筛选条件</param>
        /// <returns></returns>
        Task<DeleteResult> BatchDeleteAsync(Expression<Func<TDocument, bool>> expression);
        /// <summary>
        /// 切换仓储
        /// </summary>
        /// <typeparam name="TChangeEntity">实体类型</typeparam>
        /// <returns>仓储</returns>
        IMongoDbRepository<TChangeEntity> Change<TChangeEntity>()
                where TChangeEntity : class, IEntity<string>, new();

        /// <summary>
        /// 切换仓储
        /// </summary>
        /// <typeparam name="TChangeEntity">实体类型</typeparam>
        /// <typeparam name="TChangeKey">主键类型</typeparam>
        /// <returns>仓储</returns>
        IMongoDbRepository<TChangeEntity, TChangeKey> Change<TChangeEntity, TChangeKey>()
                where TChangeEntity : class, IEntity<TChangeKey>, new()
            where TChangeKey : class;


        /// <summary>
        /// 根据表达式查询多条记录
        /// </summary>
        /// <param name="predicate">筛选条件</param>
        /// <returns></returns>
        IQueryable<TDocument> Where(Expression<Func<TDocument, bool>> predicate);
        /// <summary>
        /// 构建查询分析器
        /// </summary>
        /// <returns></returns>
        IQueryable<TDocument> AsQueryable();
        /// <summary>
        /// 构建查询分析器
        /// </summary>
        /// <param name="predicate">筛选条件</param>
        /// <returns></returns>
        IQueryable<TDocument> AsQueryable(Expression<Func<TDocument, bool>> predicate);
        /// <summary>
        /// 直接返回数据库结果
        /// </summary>
        /// <returns></returns>
        List<TDocument> AsEnumerable();
        /// <summary>
        /// 直接返回数据库结果
        /// </summary>
        /// <returns></returns>
        Task<List<TDocument>> AsAsyncEnumerable();
        /// <summary>
        /// 直接返回数据库结果
        /// </summary>
        /// <param name="predicate">筛选条件</param>
        /// <returns></returns>

        List<TDocument> AsEnumerable(Expression<Func<TDocument, bool>> predicate);
        /// <summary>
        /// 直接返回数据库结果
        /// </summary>
        /// <param name="predicate">筛选条件</param>
        /// <returns></returns>

        Task<List<TDocument>> AsAsyncEnumerable(Expression<Func<TDocument, bool>> predicate);
    }
}
